package com.key.w8.http1.connection.connectionImpl;

import com.key.w8.common.execute.ChainExecuteHandler;
import com.key.w8.http1.connection.Connection;
import com.key.w8.http1.entity.HttpRequest;
import com.key.w8.http1.entity.HttpResponse;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;

import java.nio.ByteBuffer;

import static com.key.w8.http1.constant.Constants.*;

/**
 * @Author: k8
 * @CreateTime: 2025-03-02
 * @Version: 1.0
 */
public class ServerHttp1PersistentConnection extends DefaultHttp1Connection {

    public ServerHttp1PersistentConnection() {
        super.addChainExecuteHandler(new ChainExecuteHandler() {
                    @Override
                    public Object onInvoke(Object msg, Object attach) {
                        if (msg instanceof HttpRequest && attach instanceof Connection) {
                            HttpRequest request = (HttpRequest) msg;
                            Connection connection = (Connection) attach;
                            HttpHeaders headers = request.headers();
                            Object result = super.fireNextHandler(request, null);
                            HttpResponse response = null;
                            if (result == null) {
                                response = new HttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
                            } else if (result instanceof HttpResponse) {
                                response = (HttpResponse) result;
                            } else if (result instanceof byte[]) {
                                byte[] bytes = (byte[]) result;
                                response = new HttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
                                response.setData(bytes);
                                response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, bytes.length);
                            } else if (result instanceof ByteBuffer) {
                                ByteBuffer buffer = (ByteBuffer) result;
                                response = new HttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
                                response.setBuffer(buffer);
                                response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, buffer.remaining());
                            } else if (result instanceof String) {
                                String message = (String) result;
                                response = new HttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
                                response.setMessage(message);
                            } else if (result instanceof ByteBuf){
                                ByteBuf byteBuf = (ByteBuf) result;
                                response = new HttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK);
                                response.setContent(byteBuf);
                            } else{
                                response = new HttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK);
                                response.setComplexObject(result);
                            }
                            if (headers.contains(ACK_HEADER)) {
                                response.headers().set(ACK_HEADER, headers.get(ACK_HEADER));
                            }
                            connection.writeResponse(response);
                            return null;
                        } else {
                            return super.fireNextHandler(msg, attach);
                        }
                    }
                })
                .addChainExecuteHandler(new ChainExecuteHandler() {
                    @Override
                    public Object onInvoke(Object msg, Object attach) {
                        if (msg instanceof HttpRequest && ((HttpRequest) msg).headers().contains(REQUEST_ENTITY_LARGE)) {
                            HttpResponse response = new HttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE);
                            return response;
                        } else if (msg instanceof HttpRequest && ((HttpRequest) msg).headers().contains(UNABLE_TO_PARSE_REQUEST)) {
                            HttpResponse response = new HttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.UNSUPPORTED_MEDIA_TYPE);
                            return response;
                        } else {
                            try {
                                return super.fireNextHandler(msg, attach);
                            } catch (Throwable throwable) {
                                HttpResponse response = new HttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR);
                                response.setMessage(throwable.getMessage());
                                return response;
                            }
                        }
                    }
                }).addChainErrorHandler(new ChainExecuteHandler() {
                    @Override
                    public Object onInvoke(Object msg, Object attach) {
                        if (msg instanceof HttpRequest && attach instanceof ErrorEntity){
                            HttpRequest httpRequest = (HttpRequest) msg;
                            ErrorEntity errorEntity = (ErrorEntity) attach;
                            Throwable throwable = errorEntity.getThrowable();
                            Connection connection = errorEntity.getConnection();
                            HttpHeaders headers = httpRequest.headers();
                            if (headers.contains(ACK_HEADER)) {
                                HttpResponse response = new HttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR);
                                response.setMessage(throwable.getMessage());
                                response.headers().set(ACK_HEADER, headers.get(ACK_HEADER));
                                connection.writeResponse(response);
                            }
                        }
                        return super.fireNextHandler(msg,attach);
                    }
                });
    }
}
